package com.gitee.l0km.aocache;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import com.gitee.l0km.aocache.DataProtections.IdentityFilter;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.primitives.Primitives;
import com.google.common.reflect.TypeToken;

/**
 * <p>
 * 该枚举类定义了不同的数据缓存安全策略，用于在缓存数据时对数据进行不同方式的保护。
 * 每种策略都提供了一个包装函数，用于在数据存入缓存和从缓存取出时对数据进行处理。
 * </p>
 * <p>
 * 支持的安全策略包括：
 * <ul>
 * <li>{@link #NONE}：无保护策略，不采取任何额外保护措施。</li>
 * <li>{@link #CLONE}：克隆保护策略，对支持克隆操作的数据对象进行克隆处理。</li>
 * <li>{@link #DEEPCLONE}：深度克隆保护策略，对支持克隆操作的数据对象进行深度克隆处理。</li>
 * <li>{@link #IMMUTABLE}：不可变对象保护策略，尝试将数据对象转换为不可变对象。</li>
 * </ul>
 * </p>
 */
public enum SafeStrategy implements AocacheConstant{
    /**
     * 无保护策略，默认选项。<br>
     * 此策略表示在缓存数据时不采取任何额外的保护措施。
     */
    NONE{
        @Override
        <T> Function<T, T> wrapperOf(Class<T> clazz) {
            return Functions.identity();
        }
        
        /**
         * 直接返回空数组。减少计算量。
         */
        @Override
        Function<?, ?>[] wrappersOf(Class<?>[] classes) {
            return EMPTY_FUNS_ARRAY;
		}
        
        /**
         * 直接返回空数组。减少计算量。
         */
		@Override
		Function<?, ?>[] wrappersOf(Type[] types) {
			return EMPTY_FUNS_ARRAY;
		}

		/**
		 * 直接返回空数组。减少计算量。
		 */
		@Override
		Function<?, ?>[] argWrappersOf(Member member, Object target, boolean copyArgs) {
			return EMPTY_FUNS_ARRAY;
		}
        /**
         * 直接返回恒等函数。减少计算量。
         */
		@Override
		Function<?, ?> returnWrapperOf(Member member, Object target) {
			return Functions.identity();
		}
    },
    /**
     * 克隆保护策略。<br>
     * 如果数据对象支持克隆操作，在将数据保存到缓存时，保存复制数据，在从缓存提取数据时，将返回复制数据，以避免外部修改影响缓存数据。
     */
    CLONE{
		@Override
        <T> Function<T, T> wrapperOf(Class<T> clazz) {
            return DataProtections.cloneWrapperOf(clazz);
        }
        @Override
        public <T> T wrap(T input, Type inputType) {
            return DataProtections.shallowClone(input, inputType);
        }
        @Override
        public <T> T wrap(T input, Class<T> inputType) {
            return DataProtections.shallowClone(input, inputType);
        }
    },
    /**
     * 深度克隆保护策略。<br>
     * 如果数据对象支持克隆操作，在将数据保存到缓存时，保存复制数据，在从缓存提取数据时，将返回复制数据，以避免外部修改影响缓存数据。<br>
     * 与CLONE不同的是，在执行克隆操作时，当对象为非原始(primitive)类型之外的类型时，都尽可能执行深度对象复制，<br>
     * <ul>
     * <li>当对象为容器类型(数组，Map, Collection, Multimap)时，会递归执行深度复制。</li>
     * <li>当对象为Java Bean类型时会对所有字段递归执行深度复制</li>
     * <li>当对象不可变类型(如String,Integer)时,尽可能执行对象复制，对象不可复制对象比如枚举类型,Class,Method,则保持原对象</li>
     * </ul>
     */
    DEEPCLONE{
    	@Override
    	<T> Function<T, T> wrapperOf(Class<T> clazz) {
    		return DataProtections.deepCloneWrapperOf(clazz, IdentityFilter.PRIMITIVE);
    	}

		@Override
		<T> Function<T, T> wrapperOf(Type type) {
			return DataProtections.deepCloneWrapperOf(type, IdentityFilter.PRIMITIVE);
		}

		@Override
		<T> Function<T, T> wrapperOf(TypeToken<T> type) {
			return DataProtections.deepCloneWrapperOf(type, IdentityFilter.PRIMITIVE);
		}
        @Override
        public <T> T wrap(T input, Type inputType) {
            return DataProtections.deepClone(input, inputType, IdentityFilter.PRIMITIVE);
        }
        @Override
        public <T> T wrap(T input, Class<T> inputType) {
            return DataProtections.deepClone(input, inputType, IdentityFilter.PRIMITIVE);
        }
    },
    /**
     * [可变对象]深度克隆保护策略。<br>
     * 如果数据对象支持克隆操作，在将数据保存到缓存时，保存复制数据，在从缓存提取数据时，将返回复制数据，以避免外部修改影响缓存数据。<br>
     * 与CLONE不同的是，在执行克隆操作时，当对象为可变类型类型时，都尽可能执行深度对象复制，<br>
     * 与DEEPCLONE不同的是，该策略在深度克隆时，倾向于尽可能少的执行深度对象复制,避免对不可变对象的复制<br>
     * <ul>
     * <li>当对象为容器类型(数组，Map, Collection, Multimap)时，会递归执行深度复制。</li>
     * <li>当对象为Java Bean类型时会对所有字段递归执行深度复制</li>
     * <li>当对象或容器元素为不可变类型(如String,Integer)或不可变容器(如ImmutableMap)类型时,则保持原对象</li>
     * </ul>
     */
    MUTABLECLONE{
    	@Override
    	<T> Function<T, T> wrapperOf(Class<T> clazz) {
    		return DataProtections.deepCloneWrapperOf(clazz, IdentityFilter.IMMUTABLE);
    	}
    	
    	@Override
    	<T> Function<T, T> wrapperOf(Type type) {
    		return DataProtections.deepCloneWrapperOf(type, IdentityFilter.IMMUTABLE);
    	}
    	
    	@Override
    	<T> Function<T, T> wrapperOf(TypeToken<T> type) {
    		return DataProtections.deepCloneWrapperOf(type, IdentityFilter.IMMUTABLE);
    	}
    	@Override
    	public <T> T wrap(T input, Type inputType) {
    		return DataProtections.deepClone(input, inputType, IdentityFilter.IMMUTABLE);
    	}
    	@Override
    	public <T> T wrap(T input, Class<T> inputType) {
    		return DataProtections.deepClone(input, inputType, IdentityFilter.IMMUTABLE);
    	}
    },
    /**
     * 不可变对象保护策略。<br>
     * 如果数据对象允许转换为不可变对象，在将数据保存到缓存时，将先将数据转换为不可变对象，然后再保存。
     * 这样可以确保数据在缓存中保持不变，返回给调用者的数据也不能被修改。<br>
     * 如果数据对象不支持转换为不可变对象，则尽可能复制数据对象保存到缓存<br>
     */
    IMMUTABLE{
		@Override
        <T> Function<T, T> wrapperOf(Class<T> clazz) {
            Function<T, T> fun = DataProtections.immutableWrapperOf(clazz);
            if(fun == Functions.identity()) {
                return DataProtections.cloneWrapperOf(clazz);
            }
            return fun;
        }
    };
	
	/**
	 * 获取指定类的包装器函数。
	 * 
	 * @param <T>   泛型类型
	 * @param clazz 要包装的对象的类,不能为null
	 * @return 一个将对象包装为相同类型的函数
	 */
	abstract <T> Function<T, T> wrapperOf(Class<T> clazz);

    /**
     * 根据给定的 {@link Type} 类型获取对应的包装函数。<p>
     * 该方法会将传入的 {@code Type} 转换为原始类，然后调用 {@link #wrapperOf(Class)}
     * 方法获取包装函数。<br>
     * 最后将结果强制转换为所需的泛型类型返回。<p>
     * 
     * @param <T>  包装函数的输入和输出类型
     * @param type 要处理的类型，不能为 null
     * @return 对应类型的包装函数
     */
	@SuppressWarnings("unchecked")
    <T> Function<T, T> wrapperOf(Type type) {
		return (Function<T, T>) wrapperOf(TypeToken.of(checkNotNull(type, "type is null")).getRawType());
	}

	/**
	 * 根据给定的 {@link TypeToken} 类型获取对应的包装函数。
	 * <p>
	 * 该方法会将传入的 {@code TypeToken} 转换为原始类，然后调用 {@link #wrapperOf(Class)}
	 * 方法获取包装函数。<br>
	 * 最后将结果强制转换为所需的泛型类型返回。
	 * <p>
	 * 
	 * @param <T>  包装函数的输入和输出类型
	 * @param type 要处理的类型令牌，不能为 null
	 * @return 对应类型的包装函数
	 */
	@SuppressWarnings("unchecked")
	<T> Function<T, T> wrapperOf(TypeToken<T> type) {
		return (Function<T, T>) wrapperOf(checkNotNull(type, "type is null").getRawType());
	}

	/**
     * 使用当前安全策略对输入对象进行包装处理。<p>
     * 该方法会检查输入对象是否为指定类的实例或者为 null，<br>
     * 然后调用对应安全策略的包装函数对输入对象进行处理。<p>
     * 
     * @param <T> 输入对象的类型
     * @param input 要包装的输入对象，可以为 null
     * @param inputType 输入对象的类，不能为 null
     * @return 经过包装处理后的对象
     * @throws NullPointerException 如果 {@code inputType} 为 null
     * @throws IllegalArgumentException 如果 {@code input} 既不是 {@code inputType} 的实例也不为 null
     */
	@SuppressWarnings("unchecked")
	public <T> T wrap(T input, Class<T> inputType) {
        if (null == input) {
			return null;
		}
        if(null == inputType){
            inputType = (Class<T>)input.getClass();
        }else{
            checkArgument(inputType.isInstance(input), "input is must be instance of %s", inputType);
        }
		return wrapperOf(inputType).apply(input);
	}

    /**
     * 使用当前安全策略对输入对象进行包装处理，输入对象的类型由 {@link Type} 表示。<p>
     * 该方法会检查输入对象是否为指定类型的实例或者为 null，<br>
     * 然后调用对应安全策略的包装函数对输入对象进行处理。<p>
     * 
     * @param <T> 输入对象的类型
     * @param input 要包装的输入对象，可以为 null
     * @param inputType 输入对象的类型，不能为 null
     * @return 经过包装处理后的对象
     * @throws NullPointerException 如果 {@code inputType} 为 null
     * @throws IllegalArgumentException 如果 {@code input} 既不是 {@code inputType} 对应的类型实例也不为 null
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public <T> T wrap(T input, Type inputType) {
		if (null == input) {
			return null;
		}
		if(null == inputType){
            inputType = input.getClass();
        }else if(inputType instanceof Class){
            checkArgument(Primitives.wrap(((Class)inputType)).isInstance(input), "input is must be instance of %s", inputType);
        }else{
            checkArgument(Primitives.wrap(TypeToken.of(inputType).getRawType()).isInstance(input),
                    "input is must be instance of %s", inputType);
        }
        return (T) wrapperOf(inputType).apply(input);
    }
    /**
     * 使用当前安全策略对输入对象数组进行包装处理。<p>
     * 该方法会检查输入对象数组及其对应的类数组是否符合要求，<br>
     * 包括检查数组是否为 null，输入对象数组的长度是否与类数组的长度相等，<br>
     * 以及每个输入对象是否为对应类的实例或者为 null。<p>
     * 然后对每个输入对象调用对应安全策略的包装函数进行处理，<br>
     * 最终返回经过包装处理后的对象数组。<p>
     * 
     * @param input 要包装的输入对象数组，可以包含 null 元素，但数组本身不能为 null。
     * @param inputTypes 输入对象对应的类数组，数组本身不能为 null，且数组中的每个元素也不能为 null。
     * @return 经过包装处理后的对象数组。
     * @throws NullPointerException 如果 {@code input} 或 {@code inputTypes} 为 null，或者 {@code inputTypes} 数组中包含 null 元素。
     * @throws IllegalArgumentException 如果 {@code input} 数组的长度与 {@code inputTypes} 数组的长度不相等，<br>
     * 或者 {@code input} 数组中的某个元素既不是对应 {@code inputTypes} 数组中类的实例也不为 null。
     */
	@SuppressWarnings("unchecked")
	public Object[] wrap(Object[] input, Class<?>[] inputTypes) {
		checkNotNull(input, "input can not be null");
		checkNotNull(inputTypes, "inputTypes can not be null");
		checkArgument(input.length == inputTypes.length, "input length must equal to inputTypes length");
		Object[] output = new Object[input.length];
		for (int i = 0; i < input.length; i++) {
			Object obj = input[i];
			Class<?> clazz = checkNotNull(inputTypes[i], "inputTypes[%s] is null", i);
			checkArgument(null == obj || clazz.isInstance(obj), "input[%s] is must be instance of %s or null", i,
					clazz);
			output[i] = ((Function<Object, Object>) wrapperOf(clazz)).apply(obj);
		}
		return output;
	}

    /**
     * 使用当前安全策略对输入对象数组进行包装处理，输入对象的类型由 {@link Type} 数组表示。<p>
     * 该方法会检查输入对象数组及其对应的类型数组是否符合要求，<br>
     * 包括检查数组是否为 null，输入对象数组的长度是否与类型数组的长度相等，<br>
     * 以及每个输入对象是否为对应类型的实例或者为 null。<p>
     * 然后对每个输入对象调用对应安全策略的包装函数进行处理，<br>
     * 最终返回经过包装处理后的对象数组。<p>
     * 
     * @param input 要包装的输入对象数组，可以包含 null 元素，但数组本身不能为 null。
     * @param inputTypes 输入对象对应的类型数组，数组本身不能为 null，且数组中的每个元素也不能为 null。
     * @return 经过包装处理后的对象数组。
     * @throws NullPointerException 如果 {@code input} 或 {@code inputTypes} 为 null，或者 {@code inputTypes} 数组中包含 null 元素。
     * @throws IllegalArgumentException 如果 {@code input} 数组的长度与 {@code inputTypes} 数组的长度不相等，<br>
     * 或者 {@code input} 数组中的某个元素既不是对应 {@code inputTypes} 数组中类型的实例也不为 null。
     */
    public Object[] wrap(Object[] input, Type[] inputTypes) {
		checkNotNull(input, "input can not be null");
		checkNotNull(inputTypes, "inputTypes can not be null");
		checkArgument(input.length == inputTypes.length, "input length must equal to inputTypes length");
		Object[] output = new Object[input.length];
		for (int i = 0; i < input.length; i++) {
			Object obj = input[i];
			Type type = checkNotNull(inputTypes[i], "inputTypes[%s] is null", i);
			checkArgument(null == obj || Primitives.wrap(TypeToken.of(type).getRawType()).isInstance(obj),
					"input[%s] is must be instance of %s or null", i, type);
			output[i] = ((Function<Object, Object>) wrapperOf(type)).apply(obj);
		}
		return output;
	}
    /**
     * 根据给定的类数组生成对应的包装函数数组。<p>
     * 此方法会遍历传入的类数组，为每个类调用{@link #wrapperOf(Class)}方法生成包装函数。<br>
     * 如果类数组不为空且至少有一个类的包装函数不是恒等函数，则返回包含所有包装函数的数组；<br>
     * 否则返回一个空的包装函数数组。<p>
     * 
     * @param classes 类数组，不能为null。
     * @return 对应类的包装函数数组，如果不需要转换则返回空数组。
     * @throws NullPointerException 如果{@code classes}为null。
     */
    Function<?, ?>[] wrappersOf(Class<?>[] classes) {
		checkNotNull(classes, "classes can not be null");
		if (classes.length > 0) {
			boolean needTransform = false;
			Function<?, ?>[] funs = new Function<?, ?>[classes.length];
			for (int i = 0; i < classes.length; i++) {
				funs[i] = wrapperOf(checkNotNull(classes[i], "classes[%s] is null", i));
				if (!needTransform && funs[i] != Functions.identity()) {
					needTransform = true;
				}
			}
			return needTransform ? funs : EMPTY_FUNS_ARRAY;
		}
		return EMPTY_FUNS_ARRAY;
	}

    /**
     * 根据给定的 {@link Type} 数组生成对应的包装函数数组。<p>
     * 此方法会遍历传入的类型数组，为每个类型调用 {@link #wrapperOf(Type)} 方法生成包装函数。<br>
     * 如果类型数组不为空且至少有一个类型的包装函数不是恒等函数，则返回包含所有包装函数的数组；<br>
     * 否则返回一个空的包装函数数组。<p>
     * 
     * @param types 类型数组，不能为 null。
     * @return 对应类型的包装函数数组，如果不需要转换则返回空数组。
     * @throws NullPointerException 如果 {@code types} 为 null。
     */
    Function<?, ?>[] wrappersOf(Type[] types) {
    	checkNotNull(types, "types can not be null");
    	if (types.length > 0) {
    		boolean needTransform = false;
    		Function<?,?>[] funs = new Function<?,?>[types.length];
    		for (int i = 0; i < types.length; i++) {
    			funs[i] = wrapperOf(checkNotNull(types[i], "types[%s] is null", i));
    			if (!needTransform && funs[i]!= Functions.identity()) {
    				needTransform = true;
    			}
    		}
    		return needTransform ? funs : EMPTY_FUNS_ARRAY;
    	}
    	return EMPTY_FUNS_ARRAY;
    }
    /**
     * 根据给定的成员对象（如方法或构造函数）和是否复制参数的标志，生成相应的包装函数数组。<p>
     * 此方法会检查传入的成员对象类型，若为方法，则获取其参数类型并调用{@link #wrappersOf(Class[])}方法生成包装函数数组；<br>
     * 若为构造函数，同样获取其参数类型并调用{@link #wrappersOf(Class[])}方法。<p>
     * 如果传入的成员对象既不是方法也不是构造函数，或者{@code copyArgs}为{@code false}，则返回一个空的包装函数数组。<p>
     * 
     * @param member 可访问对象，如方法或构造函数。不能为null。
     * @param target 用于解析类型的目标对象
     * @param copyArgs 是否复制参数的标志。如果为{@code true}，则尝试生成包装函数数组；否则返回空数组。
     * @return 对应参数类型的包装函数数组，如果不需要转换则返回空数组。
     * @throws NullPointerException 如果{@code member}为null。
     */
    Function<?,?>[] argWrappersOf(Member member, Object target, boolean copyArgs) {
    	checkNotNull(member, "member can not be null");
    	if(copyArgs) {
    		if(member instanceof Method) {
                Type[] types = AocacheUtils.resolveTypes(target, ((Method)member).getGenericParameterTypes());
    			return wrappersOf(types);
    		}else if(member instanceof Constructor) {
    			return wrappersOf(((Constructor<?>)member).getParameterTypes());
    		}    		
    	}
    	return EMPTY_FUNS_ARRAY;
    }
    /**
     * 根据给定的成员对象（如方法）生成返回值的包装函数。<p>
     * 此方法会检查传入的成员对象类型，若为方法，则获取其返回类型并调用{@link #wrapperOf(Class)}方法生成包装函数；<br>
     * 如果传入的成员对象不是方法，则返回一个表示恒等变换的函数，即不做任何处理。<p>
     * 
     * @param member 可访问对象，如方法。不能为null。
     * @param target 用于解析类型的目标对象
     * @return 返回值的包装函数，如果成员对象不是方法则返回恒等函数。
     * @throws NullPointerException 如果{@code member}为null。
     */
    Function<?,?> returnWrapperOf(Member member, Object target){
    	checkNotNull(member, "member can not be null");
    	if(member instanceof Method) {
    		Type returnType = AocacheUtils.resolveType(target, ((Method)member).getGenericReturnType());
    		return wrapperOf(returnType);
    	}else if(member instanceof Constructor) {
            return wrapperOf(((Constructor<?>)member).getDeclaringClass());
        }
        return Functions.identity();
    }
}
